package com.vecspace.database.dao;

import java.io.Serializable;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.query.NativeQuery;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.vecspace.data.model.IPagination;
import com.vecspace.database.model.QueryResult;
import com.vecspace.utils.log.HLogger;



/**使用hibernate对数据库进行操作
 * @author：
 */
public class HibernateDaoHelper extends HibernateDaoSupport {
	
	private int fetchSize = 0;

	private int maxResults = 0;
	private int timeoutSeconds = 0;
	
	public int getFetchSize() {
		return fetchSize;
	}

	public void setFetchSize(int fetchSize) {
		this.fetchSize = fetchSize;
	}

	public int getMaxResults() {
		return maxResults;
	}

	public void setMaxResults(int maxResults) {
		this.maxResults = maxResults;
	}
	
	public int getTimeoutSeconds() {
		return timeoutSeconds;
	}

	public void setTimeoutSeconds(int timeoutSeconds) {
		this.timeoutSeconds = timeoutSeconds;
	}
	
	
	/**用hibnate映射保存一个对象
	 * @param obj
	 * @throws Exception
	 *             :void
	 * @author：
	 */
	public void saveObject(Object obj) throws Exception {
		Session session = currentSession();
		try {
			session.save(obj);
			session.flush();
		}finally {
			evict(obj);
		}
	}

	/**用hibnate映射更新一个对象
	 * @param obj
	 * @author
	 */
	public void updateObject(Object obj) {
		Session session = currentSession();
		try {
			session.update(obj);
			session.flush();
		}finally {
			evict(obj);
		}
	}

	/**用hibnate映射保存或更新一个对象
	 * @param obj
	 * @author：
	 */
	public void saveOrUpdateObject(Object obj) {
		Session session = currentSession();
		try {
			session.saveOrUpdate(obj);
			session.flush();
		}finally {
			evict(obj);
		}
	}

	public  <T> T queryObject(Class<T> clazz, Serializable id) throws Exception {
		return currentSession().get(clazz, id);
	}

	/**方法功能描述：根据一条完整的标准sql语句查询出一个Hibernate对象。
	 * 调用举例：getDataRowByHSql("select a.* from a left outer join b on a.id=b.pid where b.id=?",new String[]{"100001"}); 
	 * @param sql 一个完整的标准sql语句
	 * @param params sql中对应的参数值
	 * @return
	 * @throws Exception 
	 * @author wanghua
	 */
	@SuppressWarnings("unchecked")
	public <T> T queryObjectBySql(Class<?> clazz, String sql, Object[] params) throws Exception{
		List<Object> rows = this.queryObjectListBySql(clazz, sql, params);
		if(rows != null && rows.size() > 0) {
			return (T)rows.get(0);
		}else return null;
	}

	/**方法功能描述：根据一条完整的标准sql语句查询出多个Hibernate对象。
	 * 调用举例：getDataRowByHSql("select b.* from b left outer join a on a.pid=b.id where b.id=?",new String[]{"100001"}); 
	 * @param sql 一个完整的标准sql语句
	 * @param params sql中对应的参数值
	 * @return
	 * @throws Exception 
	 * @author wanghua
	 */
	public <T> List<T> queryObjectListBySql(Class clazz, String sql, Object[] params) throws Exception{
		if(params == null) params = new Object[0];
		Session session = this.currentSession();
		try {
			NativeQuery query = session.createSQLQuery(sql);
			query.addEntity(clazz);
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
			List list = query.list();
			return list;
		} catch (Exception e) {
			throw e;
		} finally {
			
		}
	}
		
	public void deleteObject(Object obj) throws Exception {
		Session session = currentSession();
		session.delete(obj);
		session.flush();
	}

	public void deleteAllObject(List<?> entities) throws Exception {
		Session session = currentSession();
		for (Object entity : entities) {
			session.delete(entity);
		}
		session.flush();
	}

	public final int queryObjectCount(String hql, Object[] params) throws Exception {
		Query<?> query = currentSession().createQuery(hql);
		applyParametersToQuery(query, params);
		List<?> list = query.list();
		int count = 0;
		if ((list != null) && (list.size() > 0)) {
			count = Integer.parseInt(list.get(0) + "");
		}
		return count;
	}
	
	/**获取记录数，sql是一个类似 select count(*) ... 格式的查询语句*/
	private int queryDataRowsCountBySql(String sql, Object [] params) throws Exception{
		if(params == null) params = new Object[0];
		Session session = this.currentSession();
		try {
			Query<Object[]> query = session.createSQLQuery(sql);
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
			List<Object[]> list = query.list();
			if(list != null && list.size()>0){
				Object[] arr = (Object[])list.get(0);
				Object obj = arr[0];
				int rcount = Integer.parseInt(obj.toString());
				return rcount;
			}else {
				return 0;
			}
		} catch (Exception e) {
			throw e;
		} finally {
			if (session != null) {
				//releaseSession(session);
			}
		}
	}

	public final int queryObjectCount(String hql, String[] paramNames, Object[] params) throws Exception {
		Query query = currentSession().createQuery(hql);
		for(int i=0; i<paramNames.length; i++) {
			query.setParameter(paramNames[i], params[i]);
		}
		List list = query.list();
		int count = 0;
		if ((list != null) && (list.size() > 0)) {
			count = Integer.parseInt(list.get(0) + "");
		}
		return count;
	}

	public final int queryObjectCount(String countHql) throws Exception {
		Session session = currentSession();
		List list = session.createQuery(countHql).list();
		//List list = currentSession().find(hql);
		int count = 0;

		if ((list != null) && (list.size() > 0)) {
			count = Integer.parseInt(list.get(0) + "");
		}

		return count;
	}

	public final int queryObjectCount(Class clazz) throws Exception {
		List list = currentSession().createQuery("select count(*) from " + clazz.getName()).list();
		int count = 0;
		if ((list != null) && (list.size() > 0)) {
			count = Integer.parseInt(list.get(0) + "");
		}
		return count;
	}

	public <T> QueryResult<T> queryObjectListByPage(String hql, IPagination pagination) throws Exception {
		String countHql = "";
		if (pagination.isPaged()) {
			countHql = SqlAdapter.createCountSQL(hql);
		}
		Session session = this.currentSession();/// querySession();
		try {
			Query query = null;
			int count = 0;
			if (pagination.isPaged()) {
				count = queryObjectCount(countHql);
				pagination.setTotalRows(count);
				query = session.createQuery(hql);
				query.setFirstResult(pagination.getFirstRow());
				query.setMaxResults(pagination.getPageSize());
			} else {
				query = session.createQuery(hql);
			}
			
			QueryResult<T> result = new QueryResult<T>(query.list(), pagination);
			return result;
		} catch (Exception e) {
			throw e;
		} finally {
			if (session != null) {
			}
		}
	}

	public <T> List<T> queryObjectList(String hql) throws Exception {
		return (List<T>)currentSession().createQuery(hql).list();
	}

	public <T> QueryResult<T> queryObjectListByPage(String hql, Object[] params, IPagination pagination) throws Exception {
		if(params == null) params = new Object[0];
		String countHql = "";
		if (pagination.isPaged()) {
			countHql = SqlAdapter.createCountSQL(hql);
		}
		Session session = this.currentSession();
		try {
			Query query = session.createQuery(hql);
			int count = 0;
			if (pagination.isPaged()) {
				count = queryObjectCount(countHql, params);
				pagination.setTotalRows(count);
				query.setFirstResult(pagination.getFirstRow());
				query.setMaxResults(pagination.getPageSize());
			}
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
			return new QueryResult<T>(query.list(), pagination);
		} catch (Exception e) {
			throw e;
		} finally {
			if (session != null) {
				//releaseSession(session);
			}
		}
	}

	public <T> QueryResult<T> queryObjectListByPage(String hql, String[] paramNames, Object[] params, IPagination pagination) throws Exception {
		if(params == null) params = new Object[0];
		String countHql = "";
		if (pagination.isPaged()) {
			countHql = SqlAdapter.createCountSQL(hql);
		}
		Session session = this.currentSession();
		try {
			Query query = session.createQuery(hql);
			int count = 0;
			if (pagination.isPaged()) {
				count = queryObjectCount(countHql, paramNames, params);
				pagination.setTotalRows(count);
				query.setFirstResult(pagination.getFirstRow());
				query.setMaxResults(pagination.getPageSize());
			}
			for (int i = 0; i < paramNames.length; i++) {
				query.setParameter(paramNames[i], params[i]);
			}
			return new QueryResult<T>(query.list(), pagination);
		} catch (Exception e) {
			throw e;
		} finally {
			if (session != null) {
				//releaseSession(session);
			}
		}
	}
	
	public <T> QueryResult<T> queryDataRowPageBySql(Class<T> clazz ,String sql, Object [] params, IPagination pagination) throws Exception{
		String countSql = "";
		if(params == null) params = new Object[0];
		if (pagination.isPaged()) {
			countSql = SqlAdapter.createCountSQL(sql);
		}
		if(params == null) params = new Object[0];
		Session session = this.currentSession();
		try {
			NativeQuery query = session.createSQLQuery(sql);
			query.addEntity(clazz);
			int count = 0;
			if (pagination.isPaged()) {
				count = queryDataRowsCountBySql(countSql, params);
				pagination.setTotalRows(count);

				query.setFirstResult(pagination.getFirstRow());
				query.setMaxResults(pagination.getPageSize());
			}
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
			return new QueryResult<T>(query.list(), pagination);
		} catch (Exception e) {
			throw e;
		} finally {
		}
	}

	public <T> List<T>  queryObjectList(String hql, Object[] params) throws Exception {
		return (List<T>)this.queryListByHQL(hql, params);
	}
	

	public <T> List<T>  queryObjectList(String hql, String[] paramNames, Object[] params) throws Exception {
		return (List<T>)this.queryListByHQL(hql, paramNames, params);
	}
	
	/**Remove this instance from the session cache.*/
	public void evict(Object item){
		Session session = this.currentSession();
		try {
			session.evict(item);
		}catch(Exception ex) {
			HLogger.DEFAULT().error(ex.getMessage());
		}
	}
	/**Remove the instance from the session cache.*/
	public void evictList(List objList){
		Session session = this.currentSession();
		if(objList == null) {
			return;
		}
		for(Object obj : objList){
			try {
				session.evict(obj);
			}catch(Exception ex) {
				HLogger.DEFAULT().error(ex.getMessage());
			}
		}
	}
	
	protected void applyParametersToQuery(Query<?> queryObject, Object[] values) throws HibernateException {
		for(int i=0;i<values.length; i++) {
			queryObject.setParameter(i, values[i]);
		}
	}
		
	public List<?> queryListByHQL(String hql, Object[] values) throws DataAccessException {
		Session session = this.currentSession();
		Query<?> queryObject = session.createQuery(hql);
		prepareQuery(queryObject);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				queryObject.setParameter(i, values[i]);
			}
		}
		return queryObject.list();
	}
	
	public List<?> queryListByHQL(String hql, String[] paramNames, Object[] values) throws DataAccessException {
		Session session = this.currentSession();
		Query<?> queryObject = session.createQuery(hql);
		prepareQuery(queryObject);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				queryObject.setParameter(paramNames[i], values[i]);
			}
		}
		return queryObject.list();
	}
	/**
	 * Prepare the given Query object, applying cache settings and/or
	 * a transaction timeout.
	 * @param queryObject the Query object to prepare
	 * @see #setCacheQueries
	 * @see #setQueryCacheRegion
	 */
	public void prepareQuery(Query<?> queryObject) {
		if (getFetchSize() > 0) {
			queryObject.setFetchSize(getFetchSize());
		}
		if (getMaxResults() > 0) {
			queryObject.setMaxResults(getMaxResults());
		}
		if (getTimeoutSeconds() > 0) {
			queryObject.setTimeout(getTimeoutSeconds());
		}
	}
}